package com.cwh.taskcenter.system.sms;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReUtil;
import com.alibaba.cola.dto.PageResponse;
import com.alibaba.cola.exception.BizException;
import com.alibaba.fastjson.JSON;
import com.cwh.taskcenter.domain.system.model.SmsChannelProperties;
import com.cwh.taskcenter.domain.system.model.SmsTemplateAuditStatusEnum;
import com.cwh.taskcenter.domain.system.model.StatusEnum;
import com.cwh.taskcenter.external.sms.SmsClient;
import com.cwh.taskcenter.external.sms.SmsClientFactory;
import com.cwh.taskcenter.external.sms.dto.SmsTemplateRespDTO;
import com.cwh.taskcenter.system.mapper.SmsChannelMapper;
import com.cwh.taskcenter.system.mapper.SmsTemplateMapper;
import com.cwh.taskcenter.system.model.SmsChannelDO;
import com.cwh.taskcenter.system.model.SmsTemplateDO;
import com.cwh.taskcenter.system.sms.api.SmsTemplateService;
import com.cwh.taskcenter.system.sms.dto.data.SmsTemplateVO;
import com.cwh.taskcenter.system.sms.dto.query.SmsTemplatePageQry;
import com.cwh.taskcenter.util.BeanUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author cwh
 */
@Service
@Slf4j
public class SmsTemplateServiceImpl implements SmsTemplateService {

    @Autowired
    private SmsTemplateMapper smsTemplateMapper;

    @Autowired
    private SmsChannelMapper smsChannelMapper;

    @Resource
    private SmsClientFactory smsClientFactory;

    private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");


    @Override
    public Long createSmsTemplate(SmsTemplateAddCmd createReqVO) {

        // 校验短信渠道
        SmsChannelDO channelDO = validateSmsChannel(createReqVO.getChannelId());
        // 校验短信编码是否重复
        validateSmsTemplateCodeDuplicate(null, createReqVO.getCode());
        // 校验短信模板
        //validateApiTemplate(createReqVO.getChannelId(), createReqVO.getApiTemplateId());

        // 插入
        SmsTemplateDO template = BeanUtils.toBean(createReqVO, SmsTemplateDO.class);
        template.setParams(parseTemplateContentParams(template.getContent()));
        template.setChannelCode(channelDO.getCode());
        smsTemplateMapper.create(template);


        return template.getId();
    }

    @Override
    public void updateSmsTemplate(SmsTemplateAddCmd updateReqVO) {
        // 校验存在
        validateSmsTemplateExists(updateReqVO.getId());
        // 校验短信渠道
        SmsChannelDO channelDO = validateSmsChannel(updateReqVO.getChannelId());
        // 校验短信编码是否重复
        validateSmsTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode());
        // 校验短信模板
        //updateReqVO.getChannelId(), updateReqVO.getApiTemplateId());

        // 更新
        SmsTemplateDO updateObj = BeanUtils.toBean(updateReqVO, SmsTemplateDO.class);
        updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
        updateObj.setChannelCode(channelDO.getCode());
        smsTemplateMapper.update(updateObj);
    }

    @Override
    public void deleteSmsTemplate(Long id) {
        // 校验存在
        validateSmsTemplateExists(id);
        // 更新
        smsTemplateMapper.delete(id);
    }

    @Override
    public SmsTemplateVO getSmsTemplate(Long id) {
        SmsTemplateDO smsTemplateDO = smsTemplateMapper.findById(id);
        return BeanUtils.toBean(smsTemplateDO,SmsTemplateVO.class);
    }

    @Override
    public PageResponse<SmsTemplateVO> getSmsTemplatePage(SmsTemplatePageQry req) {
        PageHelper.startPage(req.getPageIndex(), req.getPageSize());
        List<SmsTemplateDO> smsTemplateDOList = smsTemplateMapper.paging(req);
        PageInfo<SmsTemplateDO> pageInfo = new PageInfo<>(smsTemplateDOList);
        List<SmsTemplateVO> resultList = smsTemplateDOList.stream().map(smsTemplateDO -> BeanUtils.toBean(smsTemplateDO, SmsTemplateVO.class))
                .collect(Collectors.toList());
        return PageResponse.of(resultList, (int)pageInfo.getTotal(), req.getPageSize(), req.getPageIndex());
    }

    public SmsChannelDO validateSmsChannel(Long channelId) {
        SmsChannelDO channelDO = smsChannelMapper.findById(channelId);
        if (channelDO == null) {
            throw new BizException("SMS_CHANNEL_NOT_EXISTS");
        }
        if (StatusEnum.isDisable(channelDO.getStatus())) {
            throw new BizException("SMS_CHANNEL_IS_DISABLE");
        }
        return channelDO;
    }

    public void validateSmsTemplateCodeDuplicate(Long id, String code) {
        SmsTemplateDO template = smsTemplateMapper.selectByCode(code);
        if (template == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的字典类型
        if (id == null) {
            throw new BizException("SMS_TEMPLATE_CODE_DUPLICATE", code);
        }
        if (!template.getId().equals(id)) {
            throw new BizException("SMS_TEMPLATE_CODE_DUPLICATE", code);
        }
    }

    /**
     * 校验 API 短信平台的模板是否有效
     *
     * @param channelId 渠道编号
     * @param apiTemplateId API 模板编号
     */
    @VisibleForTesting
    void validateApiTemplate(Long channelId, String apiTemplateId) {
        // 获得短信模板
        SmsClient smsClient = getSmsClient(channelId);
        Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
        SmsTemplateRespDTO template;
        try {
            template = smsClient.getSmsTemplate(apiTemplateId);
        } catch (Throwable ex) {
            throw new BizException("SMS_TEMPLATE_API_ERROR", ExceptionUtil.getRootCauseMessage(ex));
        }
        // 校验短信模版
        if (template == null) {
            throw new BizException("SMS_TEMPLATE_API_NOT_FOUND");
        }
        if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.CHECKING.getStatus())) {
            throw new BizException("SMS_TEMPLATE_API_AUDIT_CHECKING");
        }
        if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.FAIL.getStatus())) {
            throw new BizException("SMS_TEMPLATE_API_AUDIT_FAIL", template.getAuditReason());
        }
        Assert.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
                String.format("短信模板(%s) 审核状态(%d) 不正确", apiTemplateId, template.getAuditStatus()));
    }

    @VisibleForTesting
    String parseTemplateContentParams(String content) {
        return JSON.toJSONString(ReUtil.findAllGroup1(PATTERN_PARAMS, content));
    }

    public SmsClient getSmsClient(Long id) {
        SmsChannelDO channel = smsChannelMapper.findById(id);
        SmsChannelProperties properties = BeanUtils.toBean(channel, SmsChannelProperties.class);
        return smsClientFactory.createOrUpdateSmsClient(properties);
    }

    private void validateSmsTemplateExists(Long id) {
        if (smsTemplateMapper.findById(id) == null) {
            throw new BizException("SMS_TEMPLATE_NOT_EXISTS");
        }
    }

}
